#pragma once
#include <signal.h>
#include <string>
#include <unistd.h>
#include <jsoncpp/json/json.h>
//#include"../comm/log.hpp"
#include"../comm/util.hpp"
#include"runner.hpp"
#include"compiler.hpp"
#include <cstdio>
//#include<iostream>

namespace ns_compile_run 
{
    using namespace ns_log;
    using namespace ns_util;
    using namespace ns_runner;
    using namespace ns_compile;

    class Compile_Run
    {
    public:

        //删除临时文件
        static void RemoveTempFile(const std::string& file_name)
        {
            std::string _src=Path_file::Src(file_name);
            if(Oper_file::IsFileExit(file_name)) unlink(_src.c_str());

            std::string _exe=Path_file::Exe(file_name);
            if(Oper_file::IsFileExit(file_name)) unlink(_src.c_str());

            std::string _std_com_err=Path_file::Std_com_err(file_name);     
            if(Oper_file::IsFileExit(file_name)) unlink(_std_com_err.c_str());

            std::string _std_run_err=Path_file::Std_run_err(file_name);
            if(Oper_file::IsFileExit(file_name)) unlink(_std_run_err.c_str());

            std::string _stdin=Path_file::Std_in(file_name);
            if(Oper_file::IsFileExit(file_name)) unlink(_stdin.c_str());

            std::string _stdout=Path_file::Std_out(file_name);
            if(Oper_file::IsFileExit(file_name)) unlink(_stdout.c_str());

        }
        //code>0,运行时收到信号终止，
        //code<0，非运行错误，
        //code=0,没有错误，

        static std::string CodeToDesc(int code,const std::string& file_name)
        {
            std::string message;
            switch (code) 
            {
                case 0:
                    message="Compile and run successfully ";
                    break;
                case -1:
                    message="Code is empty！";
                    break;
                case -2:
                    message="User:Unknow default";
                    break;
                case -3://编译错误
                    message=Oper_file::ReadFile(Path_file::Std_com_err(file_name),&message,true);
                    break;
                case SIGABRT: // 6
                    message="Memory exceeds the limit!";//内存超范围
                    break;
                case SIGXCPU: // 24
                    message = "CPU usage timeout";
                    break;
                case SIGFPE: // 8
                    message = "Floating point overflow";
                    break;
                default:
                    message = "Unknow default" + std::to_string(code);
                    break; 
            }
            return message;

        }

        static void start(const std::string& in_json,std::string *out_json)
        {
            //反序列化，将json字符串转化为结构化内容
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json,in_value);//将in_json中的数据反序列化到in_value中

            
            std::string code=in_value["code"].asString();
            std::string input=in_value["input"].asString();
            int cpu_limit=in_value["cpu_limit"].asInt();

            int mem_limit=in_value["mem_limit"].asInt();
            //int cpu_limit=in_value["cpu_limit"].asInt();


            Json::Value out_value;
            int status_code=0;
            int run_erro_code=0;//运行错误信号
            std::string file_name;

        
            
            if(code.size()==0)
            {
                //错误处理，，，
                status_code=-1;//代码为空
                goto  End;
            }
    
            // 形成唯一文件名
            file_name = Oper_file::UniqFileName();

            if (!Oper_file::WriteToFile(Path_file::Src(file_name),code))
            {
                status_code=-2;//用户：未知错误（代码未写入文件）
                goto  End;
            }

            if(!Compiler::Compile(file_name))
            {
                status_code=-3;//编译错误
                goto End;
            }

            run_erro_code=Runner::Run(file_name, cpu_limit, mem_limit);
            if(0==run_erro_code)
            {
                //成功,,,
                status_code=0;
            }
            else if (run_erro_code<0) 
            {
                status_code=-2;
                //上面代码为空，写入出错，编译出错后都不用再进行后面的运行了，直接跳过就行
            }
            else //>0
            {
                status_code=run_erro_code;//       
            }

        End:
            out_value["status"]=status_code;
            out_value["reason"]=CodeToDesc(status_code,file_name);

            if(status_code==0)
            {
                std::string _stdout;
                Oper_file::ReadFile(Path_file::Std_out(file_name),&_stdout,true);
                out_value["stdout"]=_stdout;

                std::string _stderr;
                Oper_file::ReadFile(Path_file::Std_run_err(file_name),&_stderr,true);
                out_value["stderr"]=_stderr;
                //需要的是运行报错
                //out_value["stdout"]=Oper_file::ReadFile(Path_file::Std_com_err(file_name));//

            }

            Json::StyledWriter writer;
            *out_json=writer.write(out_value);

            RemoveTempFile(file_name);
        }
        
    };

} 
